#include "vbb_Flash.h"
#include <string.h>

void vbb_Flash_Init(VBB_Flash * Flash, uint32_t PageSize, uint32_t NumOfPages, SPI_TypeDef * SPIx, GPIO_TypeDef * GPIOx, uint32_t SelectPin)
{
    int i = 0;
    
    vbb_PIN_Init(&(Flash->select_pin), GPIOx, SelectPin, PIN_MODE_GENERAL_OUTPUT_PUSH_PULL);    
    vbb_PIN_Set(&(Flash->select_pin), FALSE);
    vbb_DelayMillis(100);
    vbb_PIN_Set(&(Flash->select_pin), TRUE);
    vbb_DelayMillis(100);
    
    vbb_SPI_Init(&(Flash->spi), SPIx);        
    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(100);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(100);
    
    Flash->pageSize = PageSize;    
    Flash->numOfPages = NumOfPages;    

    for (i = 0; i < 512; i++)
        vbb_SPI_WriteByte(&(Flash->spi), 0xFF);
        
    vbb_Flash_EnableWrite(Flash);
}

void vbb_Flash_Select(VBB_Flash * Flash)
{
    vbb_PIN_Set(&(Flash->select_pin), FALSE);
}

void vbb_Flash_Deselect(VBB_Flash * Flash)
{
    vbb_PIN_Set(&(Flash->select_pin), TRUE);
}


void vbb_Flash_Wait(VBB_Flash * Flash, uint32_t Flag)
{
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    
    vbb_SPI_WriteByte(&(Flash->spi), CMD_RDSR);                
    Flash->last_status = Flag;
    while (Flash->last_status & Flag)
    {
        Flash->last_status = vbb_SPI_WriteByte(&(Flash->spi), 0xFF);
        
        /*
        vbb_OUTPUT_Print("WIP:");
        vbb_OUTPUT_PrintNumberUnSigned(Flash->last_status);
        vbb_OUTPUT_Print("\r\n");
        */
    }
    
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
}

void vbb_Flash_EnableWrite(VBB_Flash * Flash)
{
    vbb_Flash_Wait(Flash, WIP);    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), CMD_WREN);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);    
    
    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);    
    vbb_SPI_WriteByte(&(Flash->spi), CMD_RDSR);                
    Flash->last_status = 0;
    while (!(Flash->last_status & WEL))
    {
        Flash->last_status = vbb_SPI_WriteByte(&(Flash->spi), 0xFF);   
        
        /*
        vbb_OUTPUT_Print("WEL:");
        vbb_OUTPUT_PrintNumberUnSigned(Flash->last_status);
        vbb_OUTPUT_Print("\r\n");        
        */
        
    }
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);    
}

void vbb_Flash_EraseSector(VBB_Flash * Flash, uint32_t Address)
{
    vbb_Flash_EnableWrite(Flash); 

    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), CMD_SE);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x00FF0000) >> 16);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x0000FF00) >> 8);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x000000FF));
    vbb_Flash_Deselect(Flash);    
    vbb_DelayMillis(5);        
    vbb_Flash_Wait(Flash, WIP);
    
    //vbb_OUTPUT_Print("DEBUG: Erase Successfully.\r\n");
}

void vbb_Flash_PageProgram(VBB_Flash * Flash, uint32_t Address)
{
    int i = 0;
    
    //vbb_OUTPUT_Print("DEBUG: Page Program ");
    
    vbb_Flash_EnableWrite(Flash);    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), CMD_PP);    
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x00FF0000) >> 16);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x0000FF00) >> 8);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x000000FF));
    for (i = 0; i < Flash->pageSize; i++)
        vbb_SPI_WriteByte(&(Flash->spi), Flash->tmpPage[i]);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
    vbb_Flash_Wait(Flash, WIP);
    
    //vbb_OUTPUT_Print("[SUCCESS]\r\n");
}

void vbb_Flash_PageRead(VBB_Flash * Flash, uint32_t Address)
{
    int i = 0;
    
    memset(Flash->tmpPage, 0, 512);
    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), CMD_READ);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x00FF0000) >> 16);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x0000FF00) >> 8);
    vbb_SPI_WriteByte(&(Flash->spi), (Address & 0x000000FF));
    
    for (i = 0; i < Flash->pageSize; i++)
        Flash->tmpPage[i] = vbb_SPI_WriteByte(&(Flash->spi), 0xFF);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
}

void vbb_Flash_EnableExtAddr(VBB_Flash * Flash)
{
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), 0x17);
    vbb_SPI_WriteByte(&(Flash->spi), 128);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
}

char vbb_Flash_IsEnableExtAddr(VBB_Flash * Flash)
{
    char r;
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), 0x16);
    r = vbb_SPI_WriteByte(&(Flash->spi), 0);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
    return r;
}

char vbb_Flash_ReadId(VBB_Flash * Flash)
{
    char r;
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), 0x9f);
    r = vbb_SPI_WriteByte(&(Flash->spi), 0);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
    return r;
}

char vbb_Flash_ReadElectronicSignature(VBB_Flash * Flash)
{
    char r;
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), 0xab);
    vbb_SPI_WriteByte(&(Flash->spi), 0xff);
    vbb_SPI_WriteByte(&(Flash->spi), 0xff);
    vbb_SPI_WriteByte(&(Flash->spi), 0xff);
    r = vbb_SPI_WriteByte(&(Flash->spi), 0);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
    return r;
}

void vbb_Flash_UnlockFlash(VBB_Flash * Flash)
{    
    vbb_Flash_Wait(Flash, WIP);    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), CMD_WREN);
    vbb_Flash_Deselect(Flash);
    vbb_DelayMillis(5);
    
    vbb_Flash_Select(Flash);
    vbb_DelayMillis(5);
    vbb_SPI_WriteByte(&(Flash->spi), 0x01);
    vbb_SPI_WriteByte(&(Flash->spi), 0x02);
    vbb_DelayMillis(5);
    vbb_Flash_Wait(Flash, WIP);
}
